using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;
using System.Web.Mvc;

namespace $safeprojectname$.Unity
{
    /// <summary>
    /// Conteneur Unity
    /// </summary>
    public sealed class IoCUnityContainer : IContainer
    {
        IUnityContainer _rootContainer;
        private string AppSettingsKey = "";

        #region Properties

        /// <summary>
        /// Conteneur Unity
        /// </summary>
        public IUnityContainer Container
        {
            get { return RootContainer; }
        }

        /// <summary>
        /// Conteneur principal Unity
        /// </summary>
        private IUnityContainer RootContainer
        {
            get
            {
                if (_disposed)
                    throw new InvalidOperationException("Disposed");

                if (_rootContainer == null)
                {
                    var appSettings = ConfigurationManager.AppSettings;
                    var unityConfigFile = appSettings["unityConfigFile"] ?? "Unity";
                    var defaultIoCContainer = appSettings["defaultIoCContainer"] ?? "defaultIoCContainer";

                    var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = System.Web.HttpContext.Current.Server.MapPath("~/" + unityConfigFile) };
                    System.Configuration.Configuration configuration =
                        ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
                    var unitySection = (UnityConfigurationSection)configuration.GetSection("unity");

                    _rootContainer = new UnityContainer();
                    _rootContainer.LoadConfiguration(unitySection, defaultIoCContainer);

                }
                return _rootContainer;
            }
        }
        #endregion

        /// <summary>
        /// <see cref="IContainer.Resolve{TService}"/>
        /// </summary>
        /// <typeparam name="TService"><see cref="IContainer.Resolve{TService}"/></typeparam>
        /// <returns><see cref="IContainer.Resolve{TService}"/></returns>
        public TService Resolve<TService>()
        {
            return RootContainer.Resolve<TService>();
        }

        /// <summary>
        /// <see cref="IContainer.Resolve"/>
        /// </summary>
        /// <param name="type"><see cref="IContainer.Resolve"/></param>
        /// <returns><see cref="IContainer.Resolve"/></returns>
        public object Resolve(Type type)
        {
            return RootContainer.Resolve(type, null);
        }

        /// <summary>
        /// <see cref="IContainer.RegisterType"/>
        /// </summary>
        /// <param name="type"><see cref="IContainer.RegisterType"/></param>
        public void RegisterType(Type type)
        {
            RootContainer.RegisterType(type, new TransientLifetimeManager());
        }

        /// <summary>
        /// <see cref="IContainer.RegisterType"/>
        /// </summary>
        /// <param name="interfaceType"><see cref="IContainer.RegisterType"/></param>
        /// <param name="obj">Objet à enregistrer</param>
        public void RegisterInstance(Type interfaceType, object obj)
        {
            RootContainer.RegisterInstance(interfaceType, obj);
        }

        #region IDisposable

        /// <summary>
        /// detect if alreadey disposed
        /// </summary>
        private bool _disposed;

        /// <summary>
        /// Destructeur
        /// </summary>
        ~IoCUnityContainer()
        {
            Dispose(false);
        }

        /// <summary>
        /// Fonction de ralachement de l'objet
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Fonction de ralachement de l'objet
        /// </summary>
        /// <param name="disposing">true si l'objet doit être effectivement relaché, false dans le cas contraire</param>
        private void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    if (_rootContainer != null)
                        _rootContainer.Dispose();
                }
            }
            _disposed = true;
        }

        #endregion
    }
}
